/**
 * LinkedLST, Kellen Donohue
 * May 8, 2011
 * DataSend.java - Coordinates sending data to the backend
 */
package edu.washington.cs.labspecimentransport.data;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;
import org.json.JSONObject;

import edu.washington.cs.labspecimentransport.dataobjects.*;

/**
 * @author Kellen Class to manage sending data to the backend
 */
public class DataSend<E> {

	/**
	 * The URL this DataSend hits
	 */
	private String targetURL;

	/**
	 * List of values to send
	 */
	private List<E> storedValues;

	/**
	 * Whether this DataSend has been sent once
	 */
	private boolean executed;

	/**
	 * After the DataSend is executed, the result of sending that data
	 */
	private JSONObject result;
	
	/**
	 * The request should be sent
	 */
	private HttpRequest.SendMethod sendMethod;

	/**
	 * Possible results of a data send
	 * 
	 * @author Kellen
	 */
	public enum SendResult {
		SendOK, NoConnection, ServerSideError, AlreadySent
	};

	/**
	 * Perform the data send
	 * 
	 * @return The result of executing the send
	 */
	public SendResult execute() {
		String response = null;
		if (!this.executed) {
			try {
				for (E e : this.storedValues) {
					JSONObject json = new JSONObject();
					for (Field f : e.getClass().getDeclaredFields()) {
						f.setAccessible(true);
						json.put(f.getName(), f.get(e));
					}
					 response = HttpRequest.getInstance()
							.sendRequest(targetURL, json, this.sendMethod);
					this.result = new JSONObject(response);
				}
			} catch (ClientProtocolException e) {
				e.printStackTrace();
				return SendResult.NoConnection;
			} catch (IOException e) {
				e.printStackTrace();
				return SendResult.NoConnection;
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
				return SendResult.NoConnection;
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				return SendResult.NoConnection;
			} catch (JSONException e) {
				System.err.println(response);
				e.printStackTrace();
				return SendResult.NoConnection;
			}
			this.executed = true;
			return SendResult.SendOK;
		}
		return SendResult.AlreadySent;
	}

	/**
	 * These may be created through some sort of factory, for right now don't
	 * make any until the details have been established
	 */
	private DataSend() {
		this.executed = false;
		this.storedValues = new ArrayList<E>();
		// Default to post unless we say otherwise
		this.sendMethod = HttpRequest.SendMethod.POST;
	}

	public static DataSend<CheckIn> sendCheckin(CheckIn ci) {
		DataSend<CheckIn> ds = new DataSend<CheckIn>();
		ds.targetURL = ("check_ins.json");
		ds.storedValues.add(ci);
		return ds;
	}

	public static DataSend<StopInstance> markLocationVisited(StopInstance si) {
		DataSend<StopInstance> ds = new DataSend<StopInstance>();
		if (si.getId() == null) {
			ds.targetURL = "/stop_instances.json";
		} else {
			ds.targetURL = "/stop_instances/set_visited/" + si.getId() + ".json";
		}
		ds.storedValues.add(si);
		return ds;
	}

	public static DataSend<LostItem> markItemLost(LostItem li) {
		DataSend<LostItem> ds = new DataSend<LostItem>();
		ds.targetURL = "/lost_items/";
		ds.storedValues.add(li);
		return ds;
	}

	/**
	 * Get the data that was returned following a DataSend
	 * 
	 * @return The data interpreted as a JSON Object
	 */
	public JSONObject getResult() {
		if (this.executed) {
			return this.result;
		} else {
			return null;
		}
	}

	public static DataSend<Courier> sendUpdatedCourier(Courier c) {
		DataSend<Courier> ds = new DataSend<Courier>();
		ds.targetURL = "/couriers/" + c.getId() + ".json";
		ds.storedValues.add(c);
		// We are sending an update, so it's a put
		ds.sendMethod = HttpRequest.SendMethod.PUT;
		return ds;
	}
}
